home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / appletalk / uab.shar / aarp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-12  |  25.2 KB  |  912 lines

  1. static char rcsid[] = "$Author: cck $ $Date: 88/09/16 17:12:10 $";
  2. static char rcsident[] = "$Header: /src/local/mac/cap/etalk/RCS/aarp.c,v 1.26 88/09/16 17:12:10 cck Rel $";
  3. static char revision[] = "$Revision: 1.26 $";
  4.  
  5. /*
  6.  * aarp.c - AppleTalk Address Resolution Protocol handler
  7.  *
  8.  * Copyright (c) 1988 by The Trustees of Columbia University 
  9.  *  in the City of New York.
  10.  *
  11.  * Permission is granted to any individual or institution to use,
  12.  * copy, or redistribute this software so long as it is not sold for
  13.  * profit, provided that this notice and the original copyright
  14.  * notices are retained.  Columbia University nor the author make no
  15.  * representations about the suitability of this software for any
  16.  * purpose.  It is provided "as is" without express or implied
  17.  * warranty.
  18.  *
  19.  *
  20.  * Edit History:
  21.  *
  22.  *  April 3, 1988  CCKim Created
  23.  *  Aug 26, 1988 Moved into seperate module from ethertalk
  24.  *
  25. */
  26.  
  27. static char columbia_copyright[] = "Copyright (c) 1988 by The Trustees of \
  28. Columbia University in the City of New York";
  29.  
  30. #include <stdio.h>
  31. #include <ctype.h>
  32. #include <sys/types.h>
  33. #include <hash.h>
  34. #include <sys/socket.h>
  35. #include <sys/ioctl.h>
  36. #include <sys/uio.h>
  37. #include <sys/time.h>
  38. #include <net/if.h>
  39. #include <netinet/in.h>
  40. #include <netinet/if_ether.h>
  41.  
  42. #include <netat/appletalk.h>
  43. #include "proto_intf.h"
  44. #include "ethertalk.h"
  45. #include "aarp_defs.h"
  46. #include "aarp.h"        /* double checks aarp.h */
  47. #include "log.h"
  48.  
  49. #define LOG_LOG 0
  50. #define LOG_BASE 1
  51. #define LOG_LOTS 9
  52.  
  53. private int aarptab_compare();
  54. private u_int aarp_compress();
  55. private caddr_t aarptab_new();
  56. private caddr_t aarptab_init();
  57. private AARP_ENTRY *aarptab_find();
  58. private AARP_ENTRY *aarptab_get();
  59. private int aarptab_delete();
  60.  
  61. export caddr_t aarp_init();
  62. export int aarp_get_host_addr();
  63. export int aarp_resolve();
  64. export int aarp_insert();
  65. export int aarp_acquire_etalk_node();
  66. private aarp_listener();
  67. private AARP_ENTRY *aarp_find_free_etalk_node();
  68. private probe_and_request_driver();
  69. private void aarp_probed();
  70. private void aarp_reply();
  71. private void aarp_request();
  72. private struct ai_host_node *host_node();
  73.  
  74. /* pointers to host ethernet and broadcast addresess */
  75. private u_char b_eaddr[EHRD] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  76.  
  77. /* list of all the node ids: DUMP ONLY  */
  78. private AARP_ENTRY *aarptab_node_list;
  79.  
  80. private AARP_ENTRY *aarptab_free_list;
  81.  
  82.  
  83. private int m_aarptab = 0;
  84. private int m_probe = 0;
  85. private int f_probe = 0;
  86.  
  87.  
  88. /* compare two ethertalk node addresses */
  89. private int
  90. aarptab_compare(k,node)
  91. struct ethertalkaddr *k;
  92. AARP_ENTRY *node;
  93. {
  94.   /* EtherTalk II fixup */
  95.   return(k->node - node->aae_pa.node);
  96. }
  97.  
  98. /* compress an ethertalk node addresses */
  99. private u_int
  100. aarptab_compress(k)
  101. struct ethertalkaddr *k;
  102. {
  103.   /* EtherTalk II fixup */
  104.   return(k->node);
  105. }
  106.  
  107. /* create a new arp table entry based upon the ethertalk node */
  108. private caddr_t
  109. aarptab_new(k)
  110. struct ethertalkaddr *k;
  111. {
  112.   AARP_ENTRY *en;
  113.  
  114.   if (aarptab_free_list) {
  115.     en = aarptab_free_list;    /* get first node */
  116.     aarptab_free_list = en->aae_next; /* and unlink from free list */
  117.     /* if dump, don't need to link into dump table, already there */
  118.   } else {
  119.     if ((en = (AARP_ENTRY *)malloc(sizeof(AARP_ENTRY))) == NULL)
  120.       return(NULL);
  121.     m_aarptab++;
  122.   }
  123.   en->aae_next = aarptab_node_list;
  124.   aarptab_node_list = en;
  125.   en->aae_flags = 0;        /* clear flags */
  126.   en->aae_used = 0;        /* clear used flag */
  127.   en->aae_ttl = 0;        /* clear ttl */
  128.   bcopy(k, &en->aae_pa, sizeof(*k)); /* copy in node address */
  129.   return((caddr_t)en);
  130. }
  131.  
  132. /* initial hash table for aarp table */
  133. private caddr_t
  134. aarptab_init()
  135. {
  136.   return(h_new(HASH_POLICY_CHAIN, HASH_TYPE_MULTIPLICATIVE,
  137.               AARP_TAB_SIZE,
  138.               aarptab_compare, aarptab_new, aarptab_compress, 
  139.               NULL, NULL, NULL));
  140. }
  141.  
  142. /* see if we need to try to speed up hash lookups */
  143. aarptab_speedup(aih)
  144. AI_HANDLE *aih;
  145. {
  146.   struct hash_statistics *s;
  147.   int nbkts;
  148.  
  149.   aih->ai_accesses = 0;        /* clear */
  150.   s = h_statistics(aih->ai_aarptab); /* get stats */
  151.   if (s->hs_davg < AI_AARPTAB_REHASH_POINT)
  152.     return;            /* nothing to do */
  153.   log(LOG_BASE, "aarp: %d buckets, %d entries",
  154.       s->hs_buckets, s->hs_used);
  155.   log(LOG_BASE, "aarp: arp hash table average lookup distance %d.%02d",
  156.       s->hs_davg / 100, s->hs_davg % 100);
  157.   /* possibly delete old entries */
  158.   if ((s->hs_buckets/2) > s->hs_used) {
  159.     log(LOG_BASE, "aarp: buckets half filled, reconsider hash function");
  160.     return;
  161.   } else {
  162.     nbkts = s->hs_buckets*2;
  163.   }
  164.   log(LOG_BASE, "aarp: rehashing table from %d buckets to %d buckets",
  165.       s->hs_buckets, nbkts);
  166.   h_rehash(aih->ai_aarptab, nbkts);
  167. }
  168.  
  169. /* find an aarp table entry given an ethertalk node address */
  170. private AARP_ENTRY *
  171. aarptab_find(aih, pa)
  172. AI_HANDLE *aih;
  173. struct ethertalkaddr *pa;
  174. {
  175.   AARP_ENTRY *r;
  176.   if ((r = (AARP_ENTRY *)h_member(aih->ai_aarptab, pa))) {
  177. #ifdef AARP_DUMP_TABLE
  178.     r->aae_used++;        /* used once more */
  179. #endif
  180.     if (aih->ai_accesses++ > AI_AARPTAB_EVAL_POINT)
  181.       aarptab_speedup(aih);
  182.   }
  183.   return(r);
  184. }
  185.  
  186. /* find an aarp table entry given an ethertalk node address */
  187. /* if not found, return a new entry */
  188. private AARP_ENTRY *
  189. aarptab_get(aih, pa)
  190. AI_HANDLE *aih;
  191. struct ethertalkaddr *pa;
  192. {
  193.   AARP_ENTRY *r;
  194.   int d, b;
  195.  
  196.   r = (AARP_ENTRY *)h_operation(HASH_OP_INSERT,aih->ai_aarptab,pa,-1,-1,&d,&b);
  197.   if (r == NULL)
  198.     return(NULL);
  199.   if (r->aae_flags == 0) {
  200.     /* EtherTalk II */
  201.     log(LOG_LOTS, "New AARP mapping for node %d, bkt %d, dist %d\n",
  202.     r->aae_pa.node);
  203.     r->aae_aarptab = aih->ai_aarptab;    /* remember */
  204.   } else {
  205.     if (aih->ai_accesses++ > AI_AARPTAB_EVAL_POINT)
  206.       aarptab_speedup(aih);
  207.   }
  208. #ifdef AARP_DUMP_TABLE
  209.   r->aae_used++;        /* bump */
  210. #endif
  211.   return(r);
  212. }
  213.  
  214. #ifdef notdef
  215. /* delete an aarp table entry  */
  216. private int
  217. aarptab_delete(aih, aa)
  218. AI_HANDLE *aih;
  219. AARP_ENTRY *aa;
  220. {
  221.  
  222.   aa->aae_flags = 0;        /* not okay */
  223.   /* EtherTalk II */
  224.   log(LOG_LOTS, "deleting arp entry: node %d", aa->aae_pa.node);
  225.   en = (AARP_ENTRY *)h_delete(aih->ai_aarptab, aa->aae_pa.node);
  226.   if (en != aa) {
  227.     log(LOG_BASE, "when deleting arp entry, freed entry was %x, wanted %x",
  228.     en, aa);
  229.   }
  230.   aa->aae_next = aarptab_free_list;
  231.   aarptab_free_list = aa;    /* mark */
  232. }
  233. #endif
  234.  
  235. /* scan arp table and see if anything needs going */
  236. aarptab_scan()
  237. {
  238.   struct timeval tv;
  239.   AARP_ENTRY *n, *np, *en, *t;
  240.  
  241.   np = NULL, n = aarptab_node_list;
  242.   while (n) {
  243.     if (n->aae_ttl <= 0) {
  244.       log(LOG_LOTS, "deleting arp entry: node %d", n->aae_pa.node);
  245.       en = (AARP_ENTRY *)h_delete(n->aae_aarptab, &n->aae_pa);
  246.       if (en != n) {
  247.     log(LOG_BASE, "when deleting arp entry, freed entry was %x, wanted %x",
  248.         en, n);
  249.       }
  250.       if (np)
  251.     np->aae_next = n->aae_next; /* unlink */
  252.       else
  253.     aarptab_node_list = n->aae_next; /* at head of list */
  254.       /* link onto free list */
  255.       t = n->aae_next;        /* remember next */
  256.       n->aae_next = aarptab_free_list;
  257.       aarptab_free_list = n;    /* mark */      /* delete it */
  258.       n = t;            /* advance n */
  259.       continue;            /* and skip regular advance */
  260.     } else
  261.       n->aae_ttl--;        /* dec. ttl */
  262.     np = n;            /* remeber previous */
  263.     n = n->aae_next;        /* advance n */
  264.   }
  265.   tv.tv_sec = AARP_SCAN_TIME;
  266.   tv.tv_usec = 0;
  267.   relTimeout(aarptab_scan, 0, &tv, TRUE);
  268. }
  269.  
  270. /*
  271.  * initialize AARP module
  272.  *
  273.  * arguments are: dev, devno of the interface
  274.  *   maxnodes specfies the maximum number of nodes wanted on this
  275.  *     interface (usually one)
  276.  *
  277.  * returns pointer to a AI_HANDLE - as caddr_t
  278.  *
  279. */
  280. caddr_t
  281. aarp_init(dev, devno, maxnodes)
  282. char *dev;
  283. int devno;
  284. int maxnodes;
  285. {
  286.   int aarp_listener();
  287.   AI_HANDLE *aih = NULL;
  288.   static int here_before = 0;
  289.   int ph = -1;
  290.  
  291.   if (!here_before) {
  292.     struct timeval tv;
  293.  
  294.     here_before = 1;
  295.     aarptab_node_list = NULL;    /* clear */
  296.     aarptab_free_list = NULL;
  297.     tv.tv_sec = AARP_SCAN_TIME;
  298.     tv.tv_usec = 0;
  299.     relTimeout(aarptab_scan, 0, &tv, TRUE);
  300.   }
  301.  
  302.   if ((ph = pi_open(ETHERTYPE_AARP, dev, devno)) < 0) {
  303.     log(L_UERR|LOG_LOG,"pi_open: aarp_init");
  304.     return(NULL);
  305.   }
  306.   if ((aih = (AI_HANDLE *)malloc(sizeof(AI_HANDLE))) == NULL)
  307.     goto giveup;
  308.   if ((aih->ai_nodes = (struct ai_host_node *)
  309.        malloc(sizeof(struct ai_host_node)*maxnodes)) == NULL)
  310.     goto giveup;
  311.  
  312.   /* clear host node table */
  313.   bzero(aih->ai_nodes, sizeof(struct ai_host_node)*maxnodes);
  314.   aih->ai_flags = 0;        /* clear flags for interface */
  315.   aih->ai_numnode = 0;        /* no nodes yet */
  316.   aih->ai_maxnode = maxnodes;    /* max # of nodes (usually 1) */
  317.   aih->ai_ph = ph;
  318.   /* get ethernet address */
  319.   if ((pi_get_ethernet_address(ph, aih->ai_eaddr)) < 0)
  320.     goto giveup;
  321.  
  322.   log(LOG_BASE, "Ethernet address for %s%d is %02x:%02x:%02x:%02x:%02x:%02x\n",
  323.       dev, devno, 
  324.       aih->ai_eaddr[0], aih->ai_eaddr[1], aih->ai_eaddr[2],
  325.       aih->ai_eaddr[3], aih->ai_eaddr[4], aih->ai_eaddr[5]);
  326.  
  327.   /* setup arp table */
  328.   if ((aih->ai_aarptab = aarptab_init()) == NULL)
  329.     goto giveup;
  330.   aih->ai_accesses = 0;        /* no access to table yet */
  331.  
  332.   /* establish listener now */
  333.   pi_listener(aih->ai_ph, aarp_listener, (caddr_t)aih);
  334.   return((caddr_t)aih);
  335.  giveup:
  336.   if (ph >= 0)
  337.     pi_close(ph);
  338.   if (aih) {
  339.     if (aih->ai_nodes)
  340.       free(aih->ai_nodes);
  341.     free(aih);
  342.   }
  343.   return(NULL);
  344. }
  345.  
  346. /*
  347.  * get a host node address
  348.  *
  349. */
  350. export int
  351. aarp_get_host_addr(aih, pa, which)
  352. AI_HANDLE *aih;
  353. struct ethertalkaddr *pa;
  354. int which;
  355. {
  356.   if (aih->ai_numnode > which &&
  357.       aih->ai_nodes[which].aihn_state == AI_NODE_OKAY) {
  358.     *pa = aih->ai_nodes[which].aihn_pa; /* copy it */
  359.     /* should we count pa node address? */
  360.     return(1);            /* one byte handled for now */
  361.   }
  362.   return(-1);
  363. }
  364.  
  365. /*
  366.  * returns -1: can't be resolved
  367.  *          0: resolving, come back later
  368.  *          1: resolved
  369.  *
  370.  * Resolves the ethernet address of the specified destination.
  371.  * Special cases are:
  372.  *   dstnode == 0xff -> broadcast
  373.  *   srcnode != ourselves - error
  374.  *   dstnode == ourselves - our hw addr (maybe should be error if we
  375.  *        can't send to ourselves)
  376.  * In general, algorithm is:
  377.  *  check internal table.  If entry is valid and if the ttl is valid
  378.  *  return the address from the table
  379.  * If not in the table or ttl is bad, then do a request -- however,
  380.  *  the current packet WILL drop since the aarp request will not block
  381.  *
  382. */
  383. export int
  384. aarp_resolve(aih, tpa, wantbr, eaddr)
  385. AI_HANDLE *aih;
  386. struct ethertalkaddr *tpa;
  387. int wantbr;
  388. u_char **eaddr;
  389. {
  390.   struct timeval *tv;
  391.   AARP_ENTRY *aa;
  392.  
  393.   if (wantbr) {
  394.     *eaddr = b_eaddr;    /* want to broadcast */
  395.     return(1);
  396.   }
  397.  
  398.   /* allow target to be ourselves */
  399.   if (host_node(aih, tpa, AI_NODE_OKAY)) {
  400.     *eaddr = aih->ai_eaddr;
  401.     return(0);
  402.   }
  403.  
  404.   /* find the node in the table */
  405.   if ((aa = aarptab_find(aih, tpa)) != NULL && aa->aae_flags & AARP_OKAY) {
  406.     if (aa->aae_flags & (AARP_PERM)) {
  407.       *eaddr = aa->aae_eaddr;
  408.       return(1);
  409.     }
  410.     if (aa->aae_ttl > 0) {
  411.       *eaddr = aa->aae_eaddr;    /* yes, return valid */
  412.       return(1);
  413.     }
  414.   }
  415.   /* query on interface */
  416.   aarp_request(aih, aa, tpa);
  417.   return(0);
  418. }
  419.  
  420. /*
  421.  * call with hardware address, protocol address
  422.  * flag is TRUE if insert is "hard" FALSE o.w.
  423.  *  -- A HARD insert will smash what is there
  424.  *  -- A SOFT insert will return FALSE if the ha's don't match and
  425.  *       invalidate the cache entry
  426.  * If the insert succeeds, then the ttl is bumped to the normal level
  427.  *
  428.  * Note: aarp_insert performs the gleaning functions of the aarp spec.
  429. */
  430. export int
  431. aarp_insert(aih, ha, pa, hard)
  432. AI_HANDLE *aih;
  433. u_char *ha;
  434. struct ethertalkaddr *pa;
  435. int hard;
  436. {
  437.   AARP_ENTRY *aa;
  438.   struct timeval *tv;
  439.  
  440.   /* check to make sure ha isn't broadcast (or multicast)! */
  441.   /* EtherTalk II fixup */
  442.   log(LOG_LOTS, "Got mapping for %d", pa->node);
  443.   dumpether(LOG_LOTS, "  Address", ha);
  444.  
  445.   aa = aarptab_get(aih, pa); /* find it or get a new one */
  446.   if (aa->aae_flags & AARP_OKAY) {
  447.     if (aa->aae_flags & (AARP_PERM)) /* don't reset these */
  448.       return(FALSE);
  449.     if (hard)
  450.       /* EtherTalk II fixup */
  451.       log(LOG_LOTS, "Resetting an old mapping for node %d", pa->node);
  452.   }
  453.   /* if arp entry is in cache and we aren't doing a hard update */
  454.   /* and the hardware addresses don't match, don't do an update */
  455.   if ((aa->aae_flags & AARP_OKAY) && !hard) {
  456.     if (bcmp((caddr_t)aa->aae_eaddr, (caddr_t)ha, EHRD) != 0) {
  457.       log(LOG_BASE, "AARP RESET - ethernet address mismatch");
  458.       /* EtherTalk II fixup */
  459.       log(LOG_BASE,"node number is %d", pa->node);
  460.       dumpether(LOG_BASE, "incoming address", ha);
  461.       dumpether(LOG_BASE, "cached address",aa->aae_eaddr);
  462.       aa->aae_flags &= ~AARP_OKAY; /* there we go */
  463.       return(FALSE);
  464.     }
  465.   } else {
  466.     bcopy((caddr_t)pa, (caddr_t)&aa->aae_pa, sizeof(aa->aae_pa));
  467.     bcopy((caddr_t)ha, (caddr_t)aa->aae_eaddr, EHRD); /* copy in mapping */
  468.     aa->aae_flags = AARP_OKAY;    /* reset resolving flag if set too */
  469.   }
  470.   aa->aae_ttl = AARP_TTL;    /* reset */
  471.   return(TRUE);
  472. }
  473.  
  474. /*ARGSUSED*/
  475. private
  476. aarp_listener(fd, aih, proth)
  477. int fd;                /* dummy */
  478. AI_HANDLE *aih;
  479. int proth;
  480. {
  481.   struct ethertalkaddr *dpa, *spa;
  482.   byte *sha;
  483.   struct ether_arp arp;
  484.  
  485.   struct ai_host_node *hn;
  486.  
  487.   /* note, we use read protocol because we cannot trust incoming etalk */
  488.   /* addresses from DLI on Ultrix if sent to broadcast */
  489.   if (pi_read(aih->ai_ph, &arp, sizeof(arp)) < 0)
  490.     return;
  491.  
  492.   if (ntohs(arp.arp_hrd) != ARPHRD_ETHER || /* not ethernet? */
  493.       ntohs(arp.arp_pro) != ETHERTYPE_APPLETALK || /* not appletalk? */
  494.       arp.arp_hln != EHRD ||    /* wrong hrdwr length */
  495.       arp.arp_pln != ETPL) {    /* wrong protocol length? */
  496.     /* maybe log? */
  497.     return;            /* yes, to one, kill packet */
  498.   }
  499.  
  500.   dpa = (struct ethertalkaddr *)arp.arp_tpa; /* reformat */
  501.   spa = (struct ethertalkaddr *)arp.arp_spa; /* reformat */
  502.   /* copy these because sunos4.0 they are struct's rather than arrays */
  503.   /* and we need to take the address and hate the way the warning */
  504.   /* messages come up, besides saves us a bit on dereferncing */
  505.   sha = (byte *)&arp.arp_sha;
  506.  
  507.   /* check dummy bytes? */
  508.   /* this is the first one of these, so ...  the reason we have an & */
  509.   /* in front of an array is that under sunos4.0, arp_sha, etc. are */
  510.   /* now structs */
  511.   if (bcmp((caddr_t)sha, (caddr_t)aih->ai_eaddr, EHRD) == 0) {
  512.     log(LOG_LOTS, "Packet from self");
  513.     return;
  514.   }
  515.   if (host_node(aih, spa, AI_NODE_OKAY)) {
  516.     /* EtherTalk II fixup */
  517.     log(LOG_BASE, "Address conflict %d\n", spa->node);
  518.   }
  519.  
  520.   switch (ntohs(arp.arp_op)) {
  521.   case ARPOP_PROBE:
  522.     if ((hn = host_node(aih, spa, 0))) {
  523.       switch (hn->aihn_state) {
  524.       case AI_NODE_OKAY:
  525.     aarp_reply(aih, &hn->aihn_pa, &arp); /* defend! */
  526.     break;
  527.       case AI_NODE_PROBE:
  528.     hn->aihn_state = AI_NODE_UNUSED;
  529.     break;
  530.       default:
  531.     break;
  532.       }
  533.       break;
  534.     }
  535.     aarp_probed(aih, sha, spa, arp); /* check over entry since we got probe */
  536.     break;
  537.   case ARPOP_REQUEST:
  538.     if (host_node(aih, spa, 0))    /* drop if request from one of */
  539.       break;            /* our address */
  540.     /* probably should be more discriminating here */
  541.     /* insert new entry */
  542.     aarp_insert(aih, sha, (struct ethertalkaddr *)arp.arp_spa, TRUE); 
  543.     if ((hn = host_node(aih, dpa, AI_NODE_OKAY)))
  544.       aarp_reply(aih, &hn->aihn_pa, &arp);
  545.     break;
  546.   case ARPOP_REPLY:
  547.     /* check to see that dpa isn't one we are probing */
  548.     /* if it is, then things are bad for that potential addr */
  549.  
  550.     if ((hn = host_node(aih, dpa, AI_NODE_PROBE))) {
  551.       hn->aihn_state = AI_NODE_UNUSED;
  552.       break;
  553.     }
  554.     /* drop if source was self (whether ready or not) */
  555.     /* don't need check before here because replies are not broadcast, */
  556.     /* so why would we get it :-) */
  557.     if (host_node(aih, spa, 0))
  558.       break;
  559.     /* mark in our tables */
  560.     aarp_insert(aih, sha, spa, TRUE);
  561.     break;
  562.   }
  563. }
  564.  
  565. /* AARP PROBE: some hooks in the listener too */
  566. /*
  567.  * initialize and start AARP probe process
  568.  *
  569. */
  570. struct aarp_aphandle {
  571.   AI_HANDLE *aaph_aih;        /* protocol handle */
  572.   AARP_ENTRY *aaph_ae;        /* request: point to node handle */
  573.   struct ai_host_node *aaph_node; /* probe: which node # probing */
  574.   struct ether_arp aaph_arp;    /* arp */
  575.   int (*aaph_callback)();    /* callback on success on request/probe */
  576.   caddr_t aaph_callback_arg;    /* and initial argument */
  577.   int aaph_callback_result;    /* this is the result */
  578.   int aaph_tries;        /* tries to do */
  579. };
  580.  
  581. /*
  582.  * acquire an ethertalk node 
  583.  * doesn't try new node address 
  584.  * callback is (*callback)(callback_arg, result)
  585.  *  where result < 0 if couldn't
  586.  *        result >= 0 ==> index of host node address for get host addr
  587.  *
  588.  * return: > 0 - bad node
  589.  *         = 0 - okay
  590.  *         < 0 - internal error
  591.  *
  592. */
  593.  
  594. /* probe state */
  595. export int
  596. aarp_acquire_etalk_node(aih, initial_node, callback, callback_arg)
  597. AI_HANDLE *aih;
  598. struct ethertalkaddr *initial_node;
  599. int (*callback)();        /* callback routine */
  600. caddr_t callback_arg;        /* arg for callback */
  601. {
  602.   struct aarp_aphandle *probe;
  603.   struct ai_host_node *ahn;
  604.   int whichnode = -1;
  605.   int i;
  606.     
  607.   /* bad node */
  608.   /* EtherTalk II fixup */
  609.   if (initial_node->node == 0 || initial_node->node == 255)
  610.     return(1);
  611.   if (aarptab_find(aih, initial_node) || host_node(aih, initial_node, 0)) {
  612.     /* callback ? */
  613.     return(1);
  614.   }
  615.  
  616.   /* get probe structure */
  617.   probe = (struct aarp_aphandle *)malloc(sizeof(struct aarp_aphandle));
  618.   if (probe == NULL)
  619.     return(-1);
  620.   m_probe++;
  621.   for (ahn = aih->ai_nodes, i = 0; i < aih->ai_numnode; i++, ahn++) {
  622.     if (ahn->aihn_state)    /* node in use or in probe */
  623.       continue;
  624.     whichnode = i;        /* got a good one, ahn set */
  625.     break;
  626.   }
  627.   if (whichnode < 0) {        /* no node allocate? */
  628.     if (aih->ai_numnode >= aih->ai_maxnode) /* can't */
  629.       return(-1);
  630.     whichnode = aih->ai_numnode++; /* next node */
  631.     ahn = &aih->ai_nodes[whichnode]; /* get node */
  632.   }
  633.  
  634.   /* initialize probe arp packet */
  635.   bzero(&probe->aaph_arp, sizeof(probe->aaph_arp));
  636.   probe->aaph_arp.arp_hrd = htons(ARPHRD_ETHER);
  637.   probe->aaph_arp.arp_pro = htons(ETHERTYPE_APPLETALK);
  638.   probe->aaph_arp.arp_op = htons(ARPOP_PROBE);
  639.   probe->aaph_arp.arp_hln = EHRD;
  640.   probe->aaph_arp.arp_pln = ETPL;
  641.   bcopy((caddr_t)aih->ai_eaddr, (caddr_t)&probe->aaph_arp.arp_sha, EHRD);
  642.  
  643.   bcopy((caddr_t)initial_node, (caddr_t)probe->aaph_arp.arp_spa, ETPL);
  644.   bcopy((caddr_t)initial_node, (caddr_t)probe->aaph_arp.arp_tpa, ETPL);
  645.  
  646.   probe->aaph_tries = AARP_PROBE_TRY;
  647.  
  648.   probe->aaph_callback = callback;
  649.   probe->aaph_callback_arg = callback_arg;
  650.  
  651.   probe->aaph_aih = aih;    /* handle for interface */
  652.   probe->aaph_ae = NULL;    /* mark as none */
  653.  
  654.   probe->aaph_callback_result = whichnode; /* mark */
  655.   probe->aaph_node = ahn;    /* remember it */
  656.   ahn->aihn_state = AI_NODE_PROBE; /* mark in probe state */
  657.   ahn->aihn_pa = *initial_node;    /* copy pa */
  658.  
  659.   /* do first probe */
  660.   probe_and_request_driver(probe);
  661.   return(0);            /* okay, we are trying! */
  662. }
  663.  
  664. /* main probe and request driver */
  665. private
  666. probe_and_request_driver(aphandle)
  667. struct aarp_aphandle *aphandle;
  668. {
  669.   register AARP_ENTRY *enp;
  670.  
  671.   struct timeval tv;
  672.   struct ai_host_node *ahn;
  673.   AI_HANDLE *aih = aphandle->aaph_aih;
  674.  
  675.   /* either of these can be running or both - both really doesn't */
  676.   /* make much sense though */
  677.   enp = aphandle->aaph_ae;        /* get pointer to node handle */
  678.   ahn = aphandle->aaph_node;
  679.  
  680.   if (enp && ahn) {
  681.     log(LOG_LOG, "internal error: probe and request set in aarp driver\n");
  682.     log(LOG_LOG|L_EXIT, "fatal: please report\n");
  683.   }
  684.  
  685.   if (enp && (enp->aae_flags & AARP_RESOLVING) == 0)
  686.     goto dofree;
  687.   if (ahn && ahn->aihn_state == AI_NODE_UNUSED) {
  688.     /* tell caller that probe for the node address failed */
  689.     if (aphandle->aaph_callback)
  690.       (*aphandle->aaph_callback)(aphandle->aaph_callback_arg, -1);
  691.     goto dofree;
  692.   }
  693.   if (aphandle->aaph_tries <= 0) { /* nothing left to do? */
  694.     /* if we are out of tries, then node has been acquired, hurrah! */
  695.     if (ahn) {
  696.       ahn->aihn_state = AI_NODE_OKAY;
  697.     }
  698.     if (enp) {
  699.       enp->aae_flags &= ~AARP_RESOLVING; 
  700.     }
  701.     if (aphandle->aaph_callback)
  702.       (*aphandle->aaph_callback)(aphandle->aaph_callback_arg,
  703.                  aphandle->aaph_callback_result);
  704.     goto dofree;
  705.   }
  706.   /* set timeout to next try */
  707.   aphandle->aaph_tries--;
  708.   if (enp) {
  709.     /* should decay based on number of tries */
  710.     tv.tv_sec = AARP_REQUEST_TIMEOUT_SEC;
  711.     tv.tv_usec = AARP_REQUEST_TIMEOUT_USEC;
  712.   }
  713.   if (ahn) {
  714.     /* set timeout to next try */
  715.     tv.tv_sec = AARP_PROBE_TIMEOUT_SEC;
  716.     tv.tv_usec = AARP_PROBE_TIMEOUT_USEC;
  717.   }
  718.   if (pi_write(aih->ai_ph,&aphandle->aaph_arp, sizeof(struct ether_arp),
  719.             b_eaddr) < 0) 
  720.     log(LOG_BASE|L_UERR, "pi_write failed: aarp driver");
  721.   /* setup timeout to next (relative timeout) */
  722.   relTimeout(probe_and_request_driver, aphandle, &tv, TRUE);
  723.   return;
  724. dofree:
  725.   while (remTimeout(probe_and_request_driver, aphandle))
  726.     /* remove while some on queue: NULL STATEMENT */;
  727.   /* address was resolving, nothing left */
  728.   free((caddr_t)aphandle);
  729.   f_probe++;
  730. }
  731.  
  732.  
  733. /* 
  734.  * got a probe on the specified ha, pa pair and pa is not one of ours
  735.  * 
  736.  * mark the mapping pair as suspect.  If the specified ha is
  737.  * different, then mark it as very suspect.  In both cases, the
  738.  * "suspect" flag is moving down the ttl of the mapping.
  739.  *
  740. */
  741. private void
  742. aarp_probed(aih, ha, pa, arp)
  743. AI_HANDLE *aih;
  744. u_char *ha;
  745. struct ethertalkaddr *pa;
  746. struct ether_arp *arp;
  747. {
  748.   AARP_ENTRY *aa;
  749.   struct timeval *tv;
  750.   int nttl;
  751.  
  752.   if ((aa = aarptab_find(aih, pa)) == NULL) /* find entry */
  753.     return;            /* nothing */
  754.   if ((aa->aae_flags & AARP_OKAY) == 0) /* nothing to do? */
  755.     return;            /* ;right */
  756.   /* get reduction factor on ttl */
  757.   nttl = (bcmp((caddr_t)ha, (caddr_t)aa->aae_eaddr, EHRD) == 0) ?
  758.     AARP_PROBED_SAME : AARP_PROBED_DIFF;
  759.   /* update ttl to lessor of new or old */
  760.   if (nttl < aa->aae_ttl)
  761.     aa->aae_ttl = nttl;
  762. }
  763.  
  764. /*
  765.  * reply to an arp request packet
  766.  *
  767.  * note, smashes the arp packet
  768.  *
  769. */
  770. private void
  771. aarp_reply(aih, pa, arp)
  772. AI_HANDLE *aih;
  773. struct ethertalkaddr *pa;
  774. struct ether_arp *arp;
  775. {
  776.   caddr_t sha, tha;
  777.  
  778.   sha = (caddr_t)&arp->arp_sha;    /* need & because can be struct */
  779.   tha = (caddr_t)&arp->arp_tha;
  780.  
  781.   bcopy(sha, tha, EHRD);
  782.   bcopy((caddr_t)arp->arp_spa, (caddr_t)arp->arp_tpa, ETPL);
  783.   arp->arp_op = htons(ARPOP_REPLY);
  784.   bcopy((caddr_t)aih->ai_eaddr, sha, EHRD);
  785.   /* copy in our node */
  786.   bcopy((caddr_t)pa, (caddr_t)arp->arp_spa, ETPL);
  787.   if (pi_write(aih->ai_ph, arp, sizeof(*arp), tha) < 0) {
  788.     log(LOG_LOG|L_UERR, "etsend");
  789.   }
  790. }
  791.  
  792. /*
  793.  * do an aarp request
  794.  * - doesn't check that target is ourselves
  795. */
  796. private void
  797. aarp_request(aih, snode, tpa)
  798. AI_HANDLE *aih;
  799. AARP_ENTRY *snode;
  800. struct ethertalkaddr *tpa;
  801. {
  802.   AARP_ENTRY *aa;
  803.   struct aarp_aphandle *ap;
  804.  
  805.   if ((aa = aarptab_get(aih, tpa)) == NULL) /* get new */
  806.     return;
  807.   if (aa->aae_flags & (AARP_RESOLVING))
  808.     return;
  809.   /* bad condition */
  810.   if (aa->aae_flags & (AARP_PERM))
  811.     return;
  812.   ap = (struct aarp_aphandle *)malloc(sizeof(struct aarp_aphandle));
  813.   m_probe++;
  814.   aa->aae_pa = *tpa;
  815.   aa->aae_flags |= AARP_RESOLVING;
  816.   aa->aae_flags &= ~AARP_OKAY;    /* make sure! (can be) */
  817.  
  818.   /* establish arp packet */
  819.   bzero(&ap->aaph_arp, sizeof(ap->aaph_arp));
  820.   ap->aaph_arp.arp_op = htons(ARPOP_REQUEST);
  821.   ap->aaph_arp.arp_hrd = htons(ARPHRD_ETHER);
  822.   ap->aaph_arp.arp_pro = htons(ETHERTYPE_APPLETALK);
  823.   ap->aaph_arp.arp_hln = EHRD;
  824.   ap->aaph_arp.arp_pln = ETPL;
  825.   bcopy((caddr_t)snode->aae_eaddr, (caddr_t)&ap->aaph_arp.arp_sha, EHRD);
  826.   bcopy((caddr_t)&snode->aae_pa, (caddr_t)ap->aaph_arp.arp_spa,
  827.     sizeof(struct ethertalkaddr));
  828.   bcopy((caddr_t)tpa, (caddr_t)ap->aaph_arp.arp_tpa, sizeof(*tpa));
  829.  
  830.   ap->aaph_ae = aa;        /* remember this for later */
  831.   ap->aaph_tries = AARP_REQUEST_TRY;
  832.   ap->aaph_node = NULL;        /* clear this */
  833.   ap->aaph_aih = aih;
  834.   ap->aaph_callback = NULL;
  835.  
  836.   probe_and_request_driver(ap);
  837. }
  838.  
  839.  
  840. /*
  841.  * See if the specified ethertalk address "n" is a host address
  842.  * return true if it is, false o.w.
  843.  *
  844.  * if flag is set, then it indicates that we only want to check against
  845.  *  host nodes in the state flag is set to.
  846.  *
  847. */
  848. private struct ai_host_node *
  849. host_node(aih, n, flag)
  850. AI_HANDLE *aih;
  851. struct ethertalkaddr *n;
  852. {
  853.   register int i = aih->ai_numnode;
  854.   register struct ai_host_node *ai_nodes = aih->ai_nodes;
  855.  
  856.   for ( ; i  ; ai_nodes++, i--)
  857.     if (ai_nodes->aihn_state) {
  858.       if (flag && ai_nodes->aihn_state != flag)
  859.     continue;
  860.       /* EtherTalk II fixup */
  861.       if (ai_nodes->aihn_pa.node && ai_nodes->aihn_pa.node == n->node)
  862.     return(ai_nodes);
  863.     }
  864.   return(NULL);
  865. }
  866.  
  867.  
  868. export
  869. aarp_dump_stats(fd, ah)
  870. FILE *fd;
  871. AI_HANDLE *ah;
  872. {
  873.   struct hash_statistics *s = h_statistics(ah->ai_aarptab);
  874.  
  875.   fprintf(fd, " aarp hash table statistics, %d nodes in use\n",
  876.       s->hs_used);
  877.   fprintf(fd, "\t%d lookups since last rehash, average distance %.02f\n",
  878.       s->hs_lnum, s->hs_lnum ? ((float)s->hs_lsum / s->hs_lnum) : 0.0);
  879.   fprintf(fd, "\t%d lookups total, average distance %.02f\n",
  880.       s->hs_clnum, s->hs_clnum ? ((float)s->hs_clsum / s->hs_clnum) : 0.0);
  881.   putc('\n', fd);
  882.   fprintf(fd, " %d aarptab entries allocated\n", m_aarptab);
  883.   fprintf(fd, " %d probe/request handles, %d freed\n", m_probe, f_probe);
  884.   putc('\n', fd);
  885. }
  886.  
  887. export
  888. aarp_dump_tables(fd, aih)
  889. FILE *fd;
  890. AI_HANDLE *aih;
  891. {
  892.   AARP_ENTRY *n;
  893.  
  894. #ifdef AARP_DUMP_TABLE
  895.   fprintf(fd," ARP table dump for interface\n");
  896.   for (n = aarptab_node_list; n ; n = n->aae_next) {
  897.     if (aih->ai_aarptab != n->aae_aarptab || n->aae_flags == 0)
  898.       continue;
  899.     fprintf(fd,
  900.        "  node %d, %02x:%02x:%02x:%02x:%02x:%02x, used %d flags %s%s%sttl %d\n",
  901.         n->aae_pa.node, 
  902.         n->aae_eaddr[0], n->aae_eaddr[1], n->aae_eaddr[2], 
  903.         n->aae_eaddr[3], n->aae_eaddr[4], n->aae_eaddr[5],
  904.         n->aae_used,
  905.         AARP_FNAME_OKAY(n->aae_flags),
  906.         AARP_FNAME_RESOLVING(n->aae_flags),
  907.         AARP_FNAME_PERM(n->aae_flags), n->aae_ttl);
  908.   }
  909.   putc('\n', fd);
  910. #endif
  911. }
  912.